package com.xcity.game.recharge;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;

import com.alibaba.fastjson.JSON;
import com.xcity.Server;
import com.xcity.db.entity.Player;
import com.xcity.db.entity.User;
import com.xcity.game.account.AccountChannel;
import com.xcity.game.account.AccountService;
import com.xcity.game.common.Cause;
import com.xcity.game.common.PlayerPool;
import com.xcity.game.event.GameEvents;
import com.xcity.game.player.cache.PlayerCacheService;
import com.xcity.pomelo.push.msg.RechargeResultPush;

import gnu.trove.map.TIntObjectMap;
import naga.x.App;
import naga.x.game.template.TemplateService;
import naga.x.util.IOUtils;
import naga.x.util.StringUtils;

public class RechargeServlet extends HttpServlet {

	static final byte[] SUCC = new byte[] { 'O', 'K' };
	static final byte[] SIGN_ERROR = new byte[] { 'S', 'I', 'G', 'N', 'E', 'R', 'R' };
	static final byte[] PARSE_ERROR = new byte[] { 'P', 'A', 'R', 'S', 'E', 'E', 'R', 'R' };
	static final byte[] ERROR = new byte[] { 'E', 'R', 'R', 'O', 'R' };
	
	static final Logger LOG = RechargeService.LOG;
	
	protected TIntObjectMap<RechargeTemplate> templates;
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		
		String base64 = req.getParameter("result");
		if (StringUtils.isEmpty(base64)) {
			response(res, ERROR);
			LOG.error("[RECHARGE ERROR]CAUSE[PARAMETER NULL]");
			return;
		}
		byte[] b = null;
		try {
			b = Base64.getDecoder().decode(base64);
		} catch (Exception e) {
			response(res, ERROR);
			LOG.error("[RECHARGE ERROR]DATA[{}]CAUSE[BASE64 DECODE ERROR]", base64);
			return;
		}
		String result = StringUtils.bytesToString(b, IOUtils.UTF8);
		if (StringUtils.isEmpty(result)) {
			response(res, ERROR);
			LOG.error("[RECHARGE ERROR]CAUSE[DATA NULL]");
			return;
		}
		String sign = req.getParameter("sign");
		if (!sign(base64).equals(sign)) {
			response(res, SIGN_ERROR);
			LOG.error("[RECHARGE ERROR]DATA[{}]CAUSE[SIGN ERROR]", result);
			return;
		}
		
		try {
			RechargeResult obj = JSON.parseObject(result, RechargeResult.class);
			RechargeTemplate template = findTemplate(obj.getProduct());
			if (template == null) {
				response(res, ERROR);
				LOG.error("[RECHARGE ERROR]DATA[{}]CAUSE[TEMPLATE NOT FOUND]", result);
				return;
			}
			long playerId = obj.getUserId();
			if (playerId == 0L) {
				// 没有uid则根据channelUid获取
				String cid = AccountChannel.forName(obj.getChannel()).withPrefix(obj.getChannelUid()); // 确保渠道用户id加上前缀
				User acc = App.getApp().getServiceManager().get(AccountService.class).find(cid);
				playerId = acc.getDefaultPlayerId();
			}
			Player player = App.getApp().getServiceManager().get(PlayerCacheService.class).find(playerId);
			if (player == null) {
				response(res, ERROR);
				LOG.error("[RECHARGE ERROR]DATA[{}]CAUSE[PLAYER NOT FOUND]", result);
				return;
			}
			String countKey = PlayerPool.PROPERTY_RECHARGE_COUNT_PREFIX + template.getId(); // 该档位累充次数pool key
			int oldVal = player.getStone();
			// 首次充值该档位，钻石翻倍
			int delta = template.isDoubleFirst() && player.getPool().getIntValue(countKey) == 0 ? template.getStone() << 1 : template.getStone();
//			if (player.isOnline()) {
//				if (delta > 0) {
//					player.addStone(delta, Cause.RECHARGE + ':' + obj.channel);
//					player.send(new RechargeResultPush(delta));
//				}
//				App.getApp().getEventManager().addEvent(GameEvents.EVENT_RECHARGE, player, obj.getMoney(), template);
//			} else {
//				if (delta > 0) {
//					player.addStone(delta, Cause.RECHARGE + ':' + obj.channel);
//					// 记录离线充值，用于成就系统
//					JSONArray arr = player.getPool().getJSONArray(PlayerPool.PROPERTY_OFFLINE_RECHARGE);
//					if (arr == null) {
//						arr = new JSONArray(2);
//					}
//					arr.add(new int[]{ obj.getMoney(), template.getId() });
//					player.poolSet(PlayerPool.PROPERTY_OFFLINE_RECHARGE, arr);
//				}
//				App.getApp().getEventManager().addEvent(GameEvents.EVENT_RECHARGE_OFFLINE, player, obj.getMoney(), template);
//			}
			
			if (delta > 0) {
				player.addStone(delta, Cause.RECHARGE + ':' + obj.channel);
			}
			if (player.isOnline()) {
				player.send(new RechargeResultPush(obj, delta));
			}
			player.poolAdd(countKey, 1);
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_RECHARGE, player, obj.getMoney(), template);
			response(res, SUCC);
			LOG.info("[RECHARGE SUCC]ID[{}]STONE[{}]DELTA[{}]{}", playerId, oldVal, delta, player.isOnline() ? "ONLINE" : "OFFLINE");
			LOG.info("[RECHARGE SUCC DETAIL]DATA[{}]ONLINE[{}]", result, player.isOnline());
		} catch (Exception e) {
			LOG.error("[RECHARGE ERROR]DATA[" + result + "]CAUSE[PARSE ERROR]", e);
		}
	}
	
	static void response(HttpServletResponse res, byte[] b) {
		res.setCharacterEncoding(IOUtils.UTF8);
		res.setStatus(HttpServletResponse.SC_OK);
		OutputStream out = null;
		try {
			out = res.getOutputStream();
			out.write(b);
			IOUtils.flushQuietly(out);
		} catch (Exception e) {
			LOG.error("[RECHARGE RESPONSE PLATFORM ERROR]", e);
		} finally {
			IOUtils.closeQuietly(out);
		}
	}
	
	static String sign(String result) {
		Map<String, String> map = new TreeMap<>();
		map.put("result", result);
		return Server.makeSign(map);
	}
	
	RechargeTemplate findTemplate(int product) {
		if (templates == null) {
			templates = App.getApp().getServiceManager().get(TemplateService.class).getTemplates(RechargeTemplate.class);
		}
		return templates.get(product);
	}
	
}
